#include "osmPathBuilder.h"

OsmPathBuilder::OsmPathBuilder(double lat, double lon) {
    getRequest(lat, lon);
}

OsmPathBuilder::~OsmPathBuilder() {
    if (this->graph_)
        delete this->graph_;
    if (this->dijstraAlg_)
        delete this->dijstraAlg_;
    this->graph_ = 0;
    this->dijstraAlg_ = 0;
}

static size_t writeCallback(void *contents, size_t size, size_t nmemb, void *userp) {
    fprintf(((FILE*) userp), "%s", (char*) contents);
    return size * nmemb;
}

std::string formatString(const std::string fmt, ...) {
    int size = 100;
    std::string str;
    va_list ap;
    while (1) {
        str.resize(size);
        va_start(ap, fmt);
        int n = vsnprintf((char *) str.c_str(), size, fmt.c_str(), ap);
        va_end(ap);
        if (n > -1 && n < size) {
            str.resize(n);
            return str;
        }
        if (n > -1)
            size = n + 1;
        else
            size *= 2;
    }
    return str;
}

void OsmPathBuilder::downloadFile(const char* url) {
    CURL *curl;
    FILE *fp;
    CURLcode res;
    curl = curl_easy_init();
    if (curl) {
        fp = fopen(REQUEST_FILENAME, "wb");
        curl_easy_setopt(curl, CURLOPT_URL, url);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeCallback);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
        res = curl_easy_perform(curl);
        curl_easy_cleanup(curl);
        fclose(fp);
    }
}

void OsmPathBuilder::getRequest(double lat, double lon) {
    double latMax = lat + COORD_VARIATION;
    double lonMax = lon + COORD_VARIATION;
    double latMin = lat - COORD_VARIATION;
    double lonMin = lon - COORD_VARIATION;
    std::string url = formatString("http://api.openstreetmap.org/api/0.6/map?bbox=%lf,%lf,%lf,%lf", lonMin, latMin, lonMax, latMax);
    downloadFile(url.c_str());
    fillTheGraph();
}

std::vector<int> OsmPathBuilder::buildShortestPath(int begin, int end, std::vector<int> avoidPoints) {


    this->dijstraAlg_ = new DijkstraAlgorithm(this->graph_->getAdjacencyMatrix(), this->graph_->getVertexId(), this->graph_->size());
    if (avoidPoints.empty())
        return dijstraAlg_->shortestPath(begin, end);
    else
        return dijstraAlg_->shortestPathExcludePoints(begin, end, avoidPoints);
}

void OsmPathBuilder::fillTheGraph() {
    Osmium::OSMFile file(REQUEST_FILENAME);
    StorageHandler storageHandl;
    Osmium::Input::read(file, storageHandl);
    this->graph_ = storageHandl.getGraph();
}
